package com.linxuan.reggie.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linxuan.reggie.dao.DishMapper;
import com.linxuan.reggie.dto.DishDto;
import com.linxuan.reggie.entity.Dish;
import com.linxuan.reggie.entity.DishFlavor;
import com.linxuan.reggie.service.DishFlavorService;
import com.linxuan.reggie.service.DishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 添加上事务注解，保证方法内部多条语句操作数据库同时成功同时失败
 */
@Slf4j
@Service
@Transactional
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {

    @Autowired
    private DishFlavorService dishFlavorService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${reggie.path}")
    private String basePath;

    /**
     * 因为涉及到多表操作，所以这里加上事务注解，要么同时成功，要么同时失败
     *
     * @param dishDto 前端传过来的数据，Controller调用该方法再传送
     */
    @Override
    public void saveWithFlavor(DishDto dishDto) {

        // 调用DishService类的save方法，将dishDto里面的菜品信息进行保存
        this.save(dishDto);

        // 菜品信息的ID，同样要将其存储至dish_flavor表
        Long id = dishDto.getId();

        // 前端传过来的口味数据
        List<DishFlavor> flavors = dishDto.getFlavors();
        // 前端传过来的口味数据是没有对应菜品信息的主键ID的，所以我们需要设置一下
        // 这里使用Lambda表达式，也可以使用流、for循环遍历等
        flavors.forEach((item) -> item.setDishId(id));

        // 保存菜品口味到菜品数据表dish_flavor
        dishFlavorService.saveBatch(flavors);
    }

    /**
     * 涉及到多表操作，所以开启注解
     *
     * @param id 查询菜品的ID
     * @return 返回DishDto
     */
    @Override
    public DishDto getByIdWithFlavor(Long id) {

        // 根据ID查询Dish信息并将值赋值给dishDto
        Dish dish = this.getById(id);
        DishDto dishDto = new DishDto();
        BeanUtils.copyProperties(dish, dishDto);

        // 查询菜品口味信息，并将菜品口味信息赋值给dishDto
        LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DishFlavor::getDishId, id);
        dishDto.setFlavors(dishFlavorService.list(lambdaQueryWrapper));

        // 返回
        return dishDto;
    }

    /**
     * 更新表并且连着DishFlavor一起更新
     * @param dishDto DishDto
     */
    @Override
    public void updateWithFlavor(DishDto dishDto) {
        // 更新dish表基本信息
        this.updateById(dishDto);

        // 删除dish_flavor与该ID相关的信息，如果修改的话太难了，不如直接删除，然后添加
        LambdaQueryWrapper<DishFlavor> dishFlavorLambdaQueryWrapper = new LambdaQueryWrapper<>();
        dishFlavorLambdaQueryWrapper.eq(DishFlavor::getDishId, dishDto.getId());
        dishFlavorService.remove(dishFlavorLambdaQueryWrapper);

        // 获取到菜品口味，但是也要加上菜品ID
        List<DishFlavor> flavors = dishDto.getFlavors();
        flavors.forEach((item) -> item.setDishId(dishDto.getId()));
        // 存储菜品口味信息
        dishFlavorService.saveBatch(flavors);

        // 删除Redis中保留的分类数据
        String key = "dish_" + dishDto.getCategoryId();
        redisTemplate.delete(key);
    }

    /**
     * 删除Dish表中信息，以及菜品口味表以及图片
     * @param ids
     */
    @Override
    public void deleteWithFlavorAndImg(String[] ids) {

        LambdaQueryWrapper<DishFlavor> dishFlavorLambdaQueryWrapper = new LambdaQueryWrapper<>();

        for (String id : ids) {
            // 获取Dish表图片名称
            Dish dish = this.getById(id);
            String image = dish.getImage();
            File file = new File(basePath + image);
            if (file.exists()) {
                log.info("图片存在，删除图片");
                file.delete();
            }

            // 删除菜品表中信息
            this.removeById(id);

            // 构造条件，删除口味表中有该ID的数据
            dishFlavorLambdaQueryWrapper.eq(DishFlavor::getDishId, id);
            dishFlavorService.remove(dishFlavorLambdaQueryWrapper);

            // 删除Redis中保留的分类数据
            String key = "dish_" + id;
            redisTemplate.delete(key);

        }
    }

    /**
     * 根据菜品分类ID查询出来菜品详细数据，组装为DishDto类型
     *
     * @param categoryId 菜品分类ID
     * @return 查询的菜品详细数据列表
     */
    @Override
    public List<DishDto> getDishDtoListByCategoryId(Long categoryId) {
        // 获取条件构造器
        LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 菜品状态为1，也就是处于起售状态的
        lambdaQueryWrapper.eq(Dish::getStatus, 1);
        // 分类ID不为空且相同
        lambdaQueryWrapper.eq(categoryId != null, Dish::getCategoryId, categoryId);
        // 设置排序，按照sort字段进行升序，按照更新时间进行降序
        lambdaQueryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
        // 查询出来该菜品分类下面的菜品列表
        List<Dish> dishList = this.list(lambdaQueryWrapper);

        List<DishDto> dishDtoList = dishList.stream().map((item) -> {
            // 将菜品数据拷贝至DishDto中
            DishDto dishDto = new DishDto();
            BeanUtils.copyProperties(item, dishDto);

            // 获取到菜品ID
            Long id = item.getId();
            // 查询出来该菜品所关联的口味信息并赋值
            LambdaQueryWrapper<DishFlavor> dishFlavorLambdaQueryWrapper = new LambdaQueryWrapper<>();
            dishFlavorLambdaQueryWrapper.eq(id != null, DishFlavor::getDishId, id);
            List<DishFlavor> dishFlavors = dishFlavorService.list(dishFlavorLambdaQueryWrapper);
            dishDto.setFlavors(dishFlavors);

            return dishDto;
        }).collect(Collectors.toList());

        return dishDtoList;
    }
}
